package cn.zyl.common.redis.api;

import cn.zyl.common.redis.beans.JedisConfigBean;
import cn.zyl.common.redis.config.JedisConfigList;
import cn.zyl.common.redis.constant.RedisConfigConstant;
import cn.zyl.common.redis.exception.RedisBaseException;
import cn.zyl.demo.common.boot.annotation.MethodHandleBoot;
import cn.zyl.demo.common.boot.beans.ResBody;
import cn.zyl.demo.common.boot.constant.CommonBootConstant;
import cn.zyl.demo.common.boot.tools.ResBodyTool;
import cn.zyl.demo.common.constant.SymbolConstant;
import cn.zyl.demo.common.enums.RegexEnum;
import cn.zyl.demo.common.tools.StringTool;
import cn.zyl.demo.common.tools.ValidTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * JedisApiController类说明: redis客户端jedis使用api
 *
 * @author wsz
 * @version v1.0
 * @date 2020-08-04
 */
@RestController
@RequestMapping(value = "/jedis",method = RequestMethod.POST)
public class JedisApiController {
    private static final Logger LOGGER = LoggerFactory.getLogger(JedisApiController.class);
    @Resource
    private JedisConfigList jedisConfig;
    @RequestMapping("")
    public String index(){ return "Hello Spring Boot jedis!"; }
    /**
     * 初始化redis连接配置，并返回
     * @param bean 配置信息实体,可以不传
     * @return 发生更新的配置实体
     */
    @RequestMapping("init")
    @MethodHandleBoot("初始化一个redis客户端jedis连接配置")
    public ResBody<Map<String, Object>> init(@RequestBody(required = false) JedisConfigBean bean){
        if(null == bean){
            bean = new JedisConfigBean();
            bean.init();
            Map<String, Object> map = new HashMap<>(CommonBootConstant.NUM_4);
            map.put("defVal", bean.toDefVal());
            map.put("remark", bean.toRemarks());
            return ResBodyTool.success(map);
        }
        jedisConfig.add(bean);
        return ResBodyTool.success(bean.toDefVal());
    }
    @RequestMapping("config")
    @MethodHandleBoot("获取指定的配置信息")
    public ResBody<Object> config(@RequestParam(required = false,name = "host") String host){
        checkHost(host);
        return ResBodyTool.success(jedisConfig.getConfig(host));
    }
    @RequestMapping("configMap")
    @MethodHandleBoot("获取所有的配置信息")
    public ResBody<Map<String, JedisConfigBean>> configMap(){
        return ResBodyTool.success(jedisConfig.getConfigMap());
    }
    @RequestMapping("ping")
    @MethodHandleBoot("ping指定redis服务器")
    public ResBody<Map<String, Object>> ping(@RequestParam(name = "host") String host){
        checkHost(host);
        Map<String, Object> map = new HashMap<>(4);
        map.put("slots", jedisConfig.getJedis(host).ping(null));
        return returnMap(host, map);
    }
    @RequestMapping("info")
    @MethodHandleBoot("获取指定redis服务器信息")
    public ResBody<Map<String, Object>> info(@RequestParam(name = "host") String host,@RequestParam(required = false,name = "section") String section){
        //section: ALL 获取所有信息
        checkHost(host);
        Map<String, Object> map = new HashMap<>(4);
        String info = jedisConfig.getJedis(host).info(section),s=null,k=null;
        map.put("info", info);
        String[] ifs = info.split("# "),kvs,kv;
        LOGGER.info("ifs:{}",ifs.length);
        Map<String, String> stringMap;
        for (int i = 0,l=ifs.length; i < l; i++) {
            s = ifs[i];
            if(StringTool.isEmpty(s.trim())){
                continue;
            }
            kvs = s.split("\\r\\n");
            stringMap = new HashMap<>(kvs.length);
            for(String ks:kvs){
                if(StringTool.isEmpty(ks.trim())){continue;}
                if(!ks.contains(":")){
                    k = ks;
                }else {
                    kv = ks.split(":");
                    stringMap.put(kv[0],kv.length>1?kv[1]:"");
                }
            }
            map.put(null == k ?("redis-"+i):k, stringMap);
        }
        return returnMap(host, map);
    }
    @RequestMapping("slots")
    @MethodHandleBoot("获取redis服务器节点和槽的映射关系")
    public ResBody<Map<String, Object>> slots(@RequestParam(name = "host") String host){
        checkHost(host);
        Map<String, Object> map = new HashMap<>(4);
        map.put("slots", jedisConfig.getJedis(host).slots());
        return returnMap(host, map);
    }
    @RequestMapping("randomKey")
    @MethodHandleBoot("获取随机key")
    public ResBody<Map<String, Object>> randomKey(@RequestParam(name = "host") String host){
        checkHost(host);
        Map<String, Object> map = jedisConfig.getJedis(host).randomKey();
        return returnMap(host, map);
    }
    @RequestMapping("get")
    @MethodHandleBoot("获取指定key信息")
    public ResBody<Map<String, Object>> get(@RequestParam(name = "host") String host,@RequestParam(name = "key") String key){
        checkHost(host);
        Map<String, Object> map = jedisConfig.getJedis(host).get(key);
        return returnMap(host, map);
    }
    @RequestMapping("scan")
    @MethodHandleBoot("通过扫描获取key列表")
    public ResBody<Map<String, Object>> scan(@RequestParam(name = "host") String host
            ,@RequestParam(name = "cursor") String cursor,@RequestParam(name = "match") String match,@RequestParam(name = "count") Integer count){
        checkHost(host);
        //扫描redis的游标，SCAN 命令每次被调用之后， 都会向用户返回一个新的游标
        cursor = StringTool.isEmpty(cursor)?"0":cursor;
        //正则匹配key,当前为全部*，建议前缀正则如：key*
        match = StringTool.isEmpty(match)?"*":match;
        //每次扫描的个数
        count = (null == count || count <= 0) ?1000:count;
        Map<String, Object> map = jedisConfig.getJedis(host).scan(cursor, match, count);
        map.put("cursor-old", cursor);
        map.put("MATCH", match);
        map.put("COUNT", count);
        return returnMap(host, map);
    }

    private ResBody<Map<String, Object>> returnMap(String host,Map<String, Object> map){
        map.put("redis-node", jedisConfig.getConfig(host));
        return ResBodyTool.success(map);
    }
    private void checkHost(String host) throws RedisBaseException {
        if(StringTool.isEmpty(host)){
            throw new RedisBaseException("请求参数不合法，请求参数 host 应该是ip地址和端口,如：'127.0.0.1'、'localhost'、'127.0.0.1:6379'等");
        }

        if(host.lastIndexOf(SymbolConstant.COLON_EN) > 0){
            //字符串中存在符号:,进行提取ip、端口
            String[] hs = host.split(SymbolConstant.COLON_EN);
            if(!ValidTool.regex(hs[1], RegexEnum.NUMBER_POSITIVE)){
                throw new RedisBaseException(hs[1]+",port is not number");
            }
            if(!ValidTool.regex(hs[1], RegexEnum.NUMBER_POSITIVE)){
                throw new RedisBaseException(hs[1]+",port is not number");
            }
            host = hs[0];
        }
        if(!RedisConfigConstant.DEFAULT_HOST.equals(host) && !ValidTool.regex(host, RegexEnum.IP)){
            throw new RedisBaseException(host + ",host is not IP");
        }
    }
}
